﻿#define PARALLEL

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Net;


namespace Mole
{
    public class UrlCheck
    {
        public String RawUrl { get; set; }
        public Uri UriInput { get; set; }
        public String Host { get; set; }
        public System.Net.IPHostEntry IPHost { get; set; }
        public Boolean ValidUri { get; set; }
        public Boolean Valid { get; set; }
        public Boolean ValidHost { get; set; }

        private Boolean DoCheckDns = Properties.Settings.Default.CheckDNS;
        private Boolean DoCheckHTTPResponse = Properties.Settings.Default.CheckURIPath;
 
        public UrlCheck()
        {
        }
        public UrlCheck(String url)
        {
            try
            {
                RawUrl = url;
                ValidUri = ParseUri();

                if (ValidUri) //uri parsed, no bad characters
                {
                    if (DoCheckDns)
                        ValidHost = CheckDns();
                    else
                        ValidHost = true;


                    if (ValidHost) //dns resolves on the host
                    {
                        if (DoCheckHTTPResponse)
                            ValidUri = CheckHTTPResponse(Host); //site path is valid
                        else
                            ValidUri = true;
                    }
                }

                #region oldcode
                ////get host from url
                //if (RawUrl.Contains('/'))
                //{
                //    String[] hostname = RawUrl.Split('/');

                //    int hostcount = 0;
                //    foreach (string s in hostname)
                //    {
                //        if (!String.IsNullOrEmpty(s))
                //        {
                //            if (String.Compare(s, "http:", true) != 0)
                //            {
                //                break;
                //            }
                //        }
                //        hostcount++;
                //    }

                //    if (hostname.Length > hostcount)
                //    {
                //        Host = hostname[hostcount];
                //    }
                //}
                //else
                //{
                //    Host = RawUrl;
                //}

                //if (!string.IsNullOrEmpty(Host))
                //{
                //    if (Host.Contains(':')) //http://test.com:8080
                //    {
                //        String[] hostname = Host.Split(new char[] { ':' }, 2);
                //        Host = hostname[0];

                //    }
                //}

                ////dns lookup
                //ValidHost = true;
                //if (Properties.Settings.Default.CheckDNS)
                //{
                //    try
                //    {
                //        IPHost = System.Net.Dns.GetHostEntry(Host);
                //        if (IPHost.AddressList.Count() > 0)
                //        {
                //            ValidHost = true;
                //        }
                //        else
                //        {
                //            ValidHost = false;
                //        }

                //    }
                //    catch (Exception ex)
                //    {
                //        System.Diagnostics.Debug.WriteLine(ex.Message);
                //        string msg = ex.Message;
                //        ValidHost = false;
                //    }
                //}


                ////Look for invalid characters
                //ValidChar = true;
                //if (Properties.Settings.Default.CheckURLChar)
                //{
                //    ValidChar = true;
                //    String[] badchar = { "\"", "<", ">" };
                //    foreach (String sbad in badchar)
                //    {
                //        if (RawUrl.Contains(sbad))
                //        {
                //            ValidChar = false;
                //        }
                //    }
                //}


                if (ValidUri && ValidHost)
                {
                    Valid = true;
                }
                else
                {
                    Valid = false;
                }
                #endregion
            }
            catch (Exception ex)
            {
                AlertOnEvent.OnAlertEvent(null, new AlertOnEventArgs(AlertOnEventArgs.MsgType.Error, "UrlCheck", RawUrl, ex.Message));
            }
       
        }


        private Boolean ParseUri()
        {
            Boolean success = false;
            try
            {
                if (!RawUrl.StartsWith("http", true, System.Globalization.CultureInfo.CurrentUICulture))
                {
                    UriInput = new Uri("http://" + RawUrl);
                }
                else
                {
                    UriInput = new Uri(RawUrl);
                }

                success = true;
                Host = UriInput.AbsoluteUri;
            }
            catch (Exception ex)
            {
                if (ex is UriFormatException)
                {
                    AlertOnEvent.OnAlertEvent(null, new AlertOnEventArgs(AlertOnEventArgs.MsgType.Info, "URI Check", RawUrl, ex.Message));
                    return false;
                }
                else
                {
                    throw;
                }
              
            }

            return success;
        }

        private Boolean CheckDns()
        {
            Boolean success = false;

            if (Properties.Settings.Default.CheckDNS)
            {
                try
                {
                    if (UriInput != null)
                    {
                        IPHost = System.Net.Dns.GetHostEntry(UriInput.DnsSafeHost);
                        if (IPHost.AddressList.Count() > 0)
                        {
                            success = true;
                        }
                    }
                }
                catch (Exception ex)
                {
                    AlertOnEvent.OnAlertEvent(null, new AlertOnEventArgs(AlertOnEventArgs.MsgType.Info, "DNS Resolve", RawUrl, ex.Message));
                }
            }

            return success;
        }

        private Boolean CheckHTTPResponse(String url)
        {
            Boolean value = false;

            try
            {
                WebRequest WebRequestObject = HttpWebRequest.Create(url);
                using (WebResponse ResponseObject = WebRequestObject.GetResponse())
                {
                    HttpWebResponse response = (HttpWebResponse)ResponseObject;
                    HttpStatusCode status = response.StatusCode;

                    if (status == HttpStatusCode.Redirect)
                    {
                        AlertOnEvent.OnAlertEvent(null, new AlertOnEventArgs(AlertOnEventArgs.MsgType.Warning, "HTTP Redirect", RawUrl, response.Headers[HttpResponseHeader.Location]));
                    }

                    value = true;
                }
            }
            catch (WebException webex)
            {
                String message;
                
                if (webex.Response != null)
                {
                    HttpWebResponse response = (HttpWebResponse)webex.Response;
                    HttpStatusCode status = response.StatusCode;
                    message = String.Format("HTTP Status: {0} [{1}]", status, webex.Message);
                }
                else
                {
                    message = String.Format("HTTP Status: {0} [{1}]",webex.Status, webex.Message);
                }
                AlertOnEvent.OnAlertEvent(null, new AlertOnEventArgs(AlertOnEventArgs.MsgType.Info, "HTTP Response", RawUrl, message));
            }

            return value;
        }

    }


    public class UrlChecklist
    {

        public List<UrlCheck> List = new List<UrlCheck>();

        public delegate void ProgressEventHandler(object sender, ProgressChangedEventArgs e);
        public event ProgressEventHandler ProgressEvent;
        protected virtual void OnProgressChange(ProgressChangedEventArgs e)
        {
            if (ProgressEvent != null)
            {
                // Invokes the delegates. 
                ProgressEvent(this, e);
            }
        }

        public delegate void CompleteEventHandler(object sender, RunWorkerCompletedEventArgs e);
        public event CompleteEventHandler CompleteEvent;
        protected virtual void OnCompleteChange(RunWorkerCompletedEventArgs e)
        {
            if (CompleteEvent != null)
            {
                // Invokes the delegates. 
                CompleteEvent(this, e);
            }
        }


        public UrlChecklist()
        {
        }

        public void Create(List<String> urls)
        {
            try
            {
                BackgroundWorker bwUrlCheck = new BackgroundWorker();
                bwUrlCheck.WorkerReportsProgress = true;
                bwUrlCheck.DoWork+=new DoWorkEventHandler(bwUrlCheck_DoWork);
                bwUrlCheck.RunWorkerCompleted+=new RunWorkerCompletedEventHandler(bwUrlCheck_RunWorkerCompleted);
                bwUrlCheck.ProgressChanged+=new ProgressChangedEventHandler(bwUrlCheck_ProgressChanged);
                //bwUrlCheck.WorkerSupportsCancellation = true;
                bwUrlCheck.RunWorkerAsync(urls);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                throw;
            }
        }


        #region background
        void bwUrlCheck_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                List = e.Result as List<UrlCheck>;
                RunWorkerCompletedEventArgs evt = new RunWorkerCompletedEventArgs(this, null, false);
                this.OnCompleteChange(evt);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                throw;
            }
        }

        void bwUrlCheck_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.OnProgressChange(e);
        }

        void bwUrlCheck_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                BackgroundWorker bw = sender as BackgroundWorker;
                List<String> urls = e.Argument as List<String>;

                List<UrlCheck> ListUrl = new List<UrlCheck>();

#if (PARALLEL)
                    lock (ListUrl)
                    {

                        System.Threading.Tasks.Parallel.ForEach<string>(urls, delegate(string url)
                        {
                            UrlCheck check = new UrlCheck(url);
                            ListUrl.Add(check);
                            int percent = (int)(((double)ListUrl.Count / (double)urls.Count) * 100);
                            bw.ReportProgress(percent, check);
                        }
                        );
                    }
#else
                foreach (string url in urls)
                {
                    UrlCheck check = new UrlCheck(url);
                    ListUrl.Add(check);
                    int percent = (int)(((double)ListUrl.Count / (double)urls.Count) * 100);
                    bw.ReportProgress(percent, check);
                }
#endif

                e.Result = ListUrl;

            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                throw;
            }
        }
        #endregion

    }

}
